from collections import Counter

from game.config import ranks


class HandEvaluator:
    HAND_RANKS = {
        "皇家同花顺": 10,
        "同花顺": 9,
        "四条": 8,
        "葫芦": 7,
        "同花": 6,
        "顺子": 5,
        "三条": 4,
        "两对": 3,
        "一对": 2,
        "高牌": 1
    }

    def __init__(self, cards):
        self.cards = sorted(cards, key=lambda card: ranks.index(card.rank), reverse=True)
        self.ranks = [card.rank for card in self.cards]
        self.suits = [card.suit for card in self.cards]
        self.rank_count = Counter(self.ranks)
        self.suit_count = Counter(self.suits)

    def is_flush(self):
        for suit, count in self.suit_count.items():
            if count >= 5:
                flush_cards = [card for card in self.cards if card.suit == suit]
                return True, flush_cards[:5]
        return False, []

    def is_straight(self):
        rank_values = sorted(set(ranks.index(card.rank) for card in self.cards), reverse=True)
        for i in range(len(rank_values) - 4):
            if rank_values[i] - rank_values[i + 4] == 4:
                straight_cards = [card for card in self.cards if ranks.index(card.rank) in rank_values[i:i + 5]]
                return True, straight_cards

        # Special case for A-2-3-4-5 straight
        if set([card.rank for card in self.cards]) >= {'A', '2', '3', '4', '5'}:
            straight_cards = [card for card in self.cards if card.rank in ('A', '2', '3', '4', '5')]
            return True, straight_cards

        return False, []

    def is_straight_flush(self):
        for suit in self.suit_count:
            suited_cards = sorted([card for card in self.cards if card.suit == suit],
                                  key=lambda card: ranks.index(card.rank), reverse=True)
            if len(suited_cards) >= 5:
                is_straight, straight_cards = self.is_straight()
                if is_straight:
                    return True, straight_cards
        return False, []

    def is_royal_flush(self):
        for suit in self.suit_count:
            suited_cards = [card for card in self.cards if card.suit == suit]
            if set([card.rank for card in suited_cards]) == {'A', 'K', 'Q', 'J', '10'}:
                return True, suited_cards[:5]
        return False, []

    def get_hand_rank(self):
        if self.is_royal_flush()[0]:
            return "皇家同花顺", self.is_royal_flush()[1], self.HAND_RANKS["皇家同花顺"]
        if self.is_straight_flush()[0]:
            return "同花顺", self.is_straight_flush()[1], self.HAND_RANKS["同花顺"]
        if 4 in self.rank_count.values():
            four_of_a_kind = [card for card in self.cards if self.rank_count[card.rank] == 4]
            remaining = [card for card in self.cards if self.rank_count[card.rank] != 4][:1]
            return "四条", four_of_a_kind + remaining, self.HAND_RANKS["四条"]
        if 3 in self.rank_count.values() and 2 in self.rank_count.values():
            three_of_a_kind = [card for card in self.cards if self.rank_count[card.rank] == 3]
            pair = [card for card in self.cards if self.rank_count[card.rank] == 2][:2]
            return "葫芦", three_of_a_kind + pair, self.HAND_RANKS["葫芦"]
        if self.is_flush()[0]:
            return "同花", self.is_flush()[1], self.HAND_RANKS["同花"]
        if self.is_straight()[0]:
            return "顺子", self.is_straight()[1], self.HAND_RANKS["顺子"]
        if 3 in self.rank_count.values():
            three_of_a_kind = [card for card in self.cards if self.rank_count[card.rank] == 3]
            remaining = [card for card in self.cards if self.rank_count[card.rank] != 3][:2]
            return "三条", three_of_a_kind + remaining, self.HAND_RANKS["三条"]
        if list(self.rank_count.values()).count(2) >= 2:
            pairs = [card for card in self.cards if self.rank_count[card.rank] == 2]
            remaining = [card for card in self.cards if self.rank_count[card.rank] != 2][:1]
            return "两对", pairs + remaining, self.HAND_RANKS["两对"]
        if 2 in self.rank_count.values():
            pair = [card for card in self.cards if self.rank_count[card.rank] == 2]
            remaining = [card for card in self.cards if self.rank_count[card.rank] != 2][:3]
            return "一对", pair + remaining, self.HAND_RANKS["一对"]
        return "高牌", self.cards[:5], self.HAND_RANKS["高牌"]

    @staticmethod
    def rank_card(card):
        ranks = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10,
                 'J': 11, 'Q': 12, 'K': 13, 'A': 14}
        return ranks[card.rank]

    @staticmethod
    def compare_high_card(hand1, hand2):
        """比较两手高牌"""
        for card1, card2 in zip(hand1, hand2):
            if ranks.index(card1.rank) > ranks.index(card2.rank):
                return 1
            elif ranks.index(card1.rank) < ranks.index(card2.rank):
                return -1
        return 0

    @staticmethod
    def compare_hands(hand1, hand2):
        """比较两手牌的大小"""
        # 判断输入类型
        if isinstance(hand1, list):
            hand1 = HandEvaluator(hand1)
        if isinstance(hand2, list):
            hand2 = HandEvaluator(hand2)

        rank1_name, rank1_cards, rank1_value = hand1.get_hand_rank()
        rank2_name, rank2_cards, rank2_value = hand2.get_hand_rank()

        if rank1_value > rank2_value:
            return 1
        elif rank1_value < rank2_value:
            return -1
        else:
            if rank1_name in ["四条", "三条", "一对"]:
                main1 = [card for card in rank1_cards if
                         hand1.rank_count[card.rank] == hand1.rank_count[rank1_cards[0].rank]]
                main2 = [card for card in rank2_cards if
                         hand2.rank_count[card.rank] == hand2.rank_count[rank2_cards[0].rank]]
                kicker1 = [card for card in rank1_cards if
                           hand1.rank_count[card.rank] != hand1.rank_count[rank1_cards[0].rank]]
                kicker2 = [card for card in rank2_cards if
                           hand2.rank_count[card.rank] != hand2.rank_count[rank2_cards[0].rank]]
                result = HandEvaluator.compare_high_card(main1, main2)
                if result == 0:
                    return HandEvaluator.compare_high_card(kicker1, kicker2)
                return result
            elif rank1_name == "两对":
                pairs1 = sorted([card for card in rank1_cards if hand1.rank_count[card.rank] == 2],
                                key=lambda card: ranks.index(card.rank), reverse=True)
                pairs2 = sorted([card for card in rank2_cards if hand2.rank_count[card.rank] == 2],
                                key=lambda card: ranks.index(card.rank), reverse=True)
                result = HandEvaluator.compare_high_card(pairs1, pairs2)
                if result == 0:
                    kicker1 = [card for card in rank1_cards if hand1.rank_count[card.rank] == 1]
                    kicker2 = [card for card in rank2_cards if hand2.rank_count[card.rank] == 1]
                    return HandEvaluator.compare_high_card(kicker1, kicker2)
                return result
            else:
                return HandEvaluator.compare_high_card(rank1_cards, rank2_cards)
